package com.wanji.single_point.service.impl;


import com.wanji.single_point.entity.Alarm;
import com.wanji.single_point.pojo.AlarmResult;
import com.wanji.single_point.pojo.PutParam;
import com.wanji.single_point.result.EventPerceiveResult;
import com.wanji.single_point.service.AlarmService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xinyingjie
 * @since 2022-07-14
 */
@Service
public class AlarmServiceImpl implements AlarmService {


    @Autowired
    private EventPerceiveResult result;


    private static Map<String, EventPerceiveResult> resultMap = new ConcurrentHashMap<>();
    private static AlarmResult alarmResult = new AlarmResult();


    private static final int parking_index = 0;
    private static final int lane_error_index = 1;
    private static final int speed_error_index = 2;
    private static final int toss_error_index = 3;
    private static final int occupy_error_index = 4;
    private static final int retrograde_index = 5;


    private static final int match_time = 10;


    /**
     * 读取真值系统和测试系统数据，并进行相应的统计分许处理
     *
     * 
     */


    @Override
    public void putData(String userId, Alarm[] alarmReals, Alarm[] alarmTests, PutParam param) {
        EventPerceiveResult result = null;
        if (!resultMap.containsKey(userId)){
            result = new EventPerceiveResult();
            result.setCountFrame(0);
        }else {
            result = resultMap.get(userId);
            result.setCountFrame(result.getCountFrame()+1);
        }

        result = eventPerceive(userId,param,result, alarmReals, alarmTests, result.getCountFrame());
        resultMap.put(userId,result);
//        System.out.println(resultMap);

    }

    @Override
    public AlarmResult getResult(String userId) {
        EventPerceiveResult result = resultMap.get(userId);
        if (result != null){
            alarmResult.setNowRealNum(result.getNow_real_num());
            alarmResult.setNowTestNum(result.getNow_test_num());
            alarmResult.setTotalRealNum(result.getTotal_real_num());
            alarmResult.setTotalTestNum(result.getTotal_test_num());
            alarmResult.setTotalRate(result.getTotal_rate());
            alarmResult.setAlarmMap(result.getAlarmMap());
            return alarmResult;
        }else {
            EventPerceiveResult result1 = new EventPerceiveResult();
            alarmResult.setNowRealNum(result1.getNow_real_num());
            alarmResult.setNowTestNum(result1.getNow_test_num());
            alarmResult.setTotalRealNum(result1.getTotal_real_num());
            alarmResult.setTotalTestNum(result1.getTotal_test_num());
            alarmResult.setTotalRate(result1.getTotal_rate());
            alarmResult.setAlarmMap(result1.getAlarmMap());
            return alarmResult;
        }


    }

    @Override
    public void deleteCache(String userId) {
        resultMap.remove(userId);
    }

    @Override
    public PutParam putParamer(String realCode, String testCode, Long beginTime, Long endTime) {
        PutParam param = new PutParam();
        param.setRealCode(realCode);
        param.setTestCode(testCode);
        param.setBeginTime(beginTime);
        param.setEndTime(endTime);
        return param;
    }


    private EventPerceiveResult eventPerceive(String userId, PutParam param, EventPerceiveResult result, Alarm[] alarm_reals, Alarm[] alarm_tests, int count_frame) {

        //根据code和时间，返回符合条件的数据
        Alarm[] alarmReals = saveAlarms(alarm_reals,param,0);
        Alarm[] alarmTests = saveAlarms(alarm_tests,param,1);
        //如果两个系统均超出了仿真时间，删除缓存，直接返回
        if (alarmReals == null && alarmTests == null){
            deleteCache(userId);
            return result;
        }


        //真值系统有数据并且设备id为目标真值id
        if (alarmReals != null) {
            //测试系统有数据并且设备id为目标测试id
            if (alarmTests != null) {
                int time_match_flag = getTimeMatchFlag(alarmReals, alarmTests, match_time);
                if (time_match_flag == 1) {
                    result = getEventNum(count_frame, result, alarmReals, alarmTests);
                } else {

                    result = AddCacheTest(count_frame, result, alarmReals);
                    result = AddCacheReal(count_frame, result, alarmTests);

                }
            } else {
                result = AddCacheTest(count_frame, result, alarmReals);
            }
        } else {
            if (alarmTests != null) {
                result = AddCacheReal(count_frame, result, alarm_tests);
            }
        }

        result = showInfo(result,count_frame);
        result = ChangeRate(result);

        return result;
    }




    private Alarm[] saveAlarms(Alarm[] Alarms_real, PutParam param, int flag) {
        List<Alarm> list = new ArrayList<>();
        for (Alarm Alarm : Alarms_real) {
            long realCreateTime = Alarm.getCreateTime();
            if (flag == 0){
                if (StringUtils.equals(Alarm.getIotDeviceCode(), param.getRealCode()) &&realCreateTime >= param.getBeginTime() &&
                        realCreateTime <= param.getEndTime()){
                    list.add(Alarm);
                }
            }
            if (flag == 1){
                if (StringUtils.equals(Alarm.getIotDeviceCode(), param.getTestCode()) &&realCreateTime >= param.getBeginTime() &&
                        realCreateTime <= param.getEndTime()){
                    list.add(Alarm);
                }
            }

        }
        if (list.size()>0){
            Alarm[] Alarms = new Alarm[list.size()];
            for (int i = 0; i < Alarms.length; i++) {
                Alarms[i] = list.get(i);
            }
            return Alarms;
        }else {
            return null;
        }
    }

    /**
     * 展示信息
     *
     *
     * @param count_frame
     */
    private EventPerceiveResult showInfo(EventPerceiveResult result, int count_frame) {
        Map<String, Map<Integer, Alarm>> match_plate_dic = result.getMatch_plate_dic();

        if (!match_plate_dic.isEmpty()) {
            for (String key : match_plate_dic.keySet()) {
                Map<Integer, Alarm> alarmMap = match_plate_dic.get(key);
                if (alarmMap.get(0).getCountFrame() == count_frame) {
                    result.setAlarmMap(alarmMap);
                    return result;
                }
            }
        }
        return result;
    }


    /**
     * 改变比率
     */
    private EventPerceiveResult ChangeRate(EventPerceiveResult result) {
        int[] total_real_num = result.getTotal_real_num();
        int[] total_rate = result.getTotal_rate();
        int[] total_test_num = result.getTotal_test_num();
        for (int i = 0; i < 6; i++) {
            if (total_real_num[i] > 0) {
                total_rate[i] = changeSum(total_test_num[i] / total_real_num[i] * 100) ;
            } else {
                if (total_real_num[i] == 0 && total_test_num[i] == 0){
                    total_rate[i] = 100;
                }

            }
        }
        result.setTotal_rate(total_rate);
        return result;
    }

    private int changeSum(int sum) {

        BigDecimal bg = new BigDecimal(sum);
        return (int)Math.round(bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
    }

    /**
     * 增加真值系统的缓存
     *
     * @param count_frame
     * @param alarm_tests
     */
    private EventPerceiveResult AddCacheReal(int count_frame, EventPerceiveResult result, Alarm[] alarm_tests) {
        Map<Integer, Alarm[]> temp_real_dic = result.getTemp_real_dic();
        Map<Integer, Alarm[]> temp_test_dic = result.getTemp_test_dic();
        if (!temp_real_dic.isEmpty()) {
            List<Integer> del_real_frame = new ArrayList<>();
            for (int realKey : temp_real_dic.keySet()) {
                Alarm[] alarm_temp = temp_real_dic.get(realKey);
                int temp_match_time_flag = getTimeMatchFlag(alarm_temp, alarm_tests, match_time);
                if (temp_match_time_flag == 1) {
                    del_real_frame.add(realKey);
                    result = getEventNum(count_frame, result, alarm_temp, alarm_tests);
                    break;
                }
            }
            if (!del_real_frame.isEmpty()) {
                for (int s : del_real_frame) {
                    temp_real_dic.remove(s);
                }
            } else {
                temp_test_dic.put(count_frame, alarm_tests);
            }
        } else {
            temp_test_dic.put(count_frame, alarm_tests);
        }
        result.setTemp_test_dic(temp_test_dic);
        result.setTemp_real_dic(temp_real_dic);
        return result;
    }

    /**
     * 增加测试系统的缓存
     *
     * @param count_frame
     * @param alarm_reals
     */
    private EventPerceiveResult AddCacheTest(int count_frame, EventPerceiveResult result, Alarm[] alarm_reals) {
        Map<Integer, Alarm[]> temp_test_dic = result.getTemp_test_dic();
        Map<Integer, Alarm[]> temp_real_dic = result.getTemp_real_dic();
        if (!temp_test_dic.isEmpty()) {
            List<Integer> del_test_frame = new ArrayList<>();
            for (int testKey : temp_test_dic.keySet()) {
                Alarm[] alarm_temp = temp_test_dic.get(testKey);
                int temp_match_time_flag = getTimeMatchFlag(alarm_reals, alarm_temp, match_time);
                if (temp_match_time_flag == 1) {
                    del_test_frame.add(testKey);
                    result = getEventNum(count_frame, result, alarm_reals, alarm_temp);
                    break;
                }
            }

            if (!del_test_frame.isEmpty()) {
                for (int s : del_test_frame) {
                    temp_test_dic.remove(s);
                }
            } else {
                temp_real_dic.put(count_frame, alarm_reals);
            }
        } else {
            temp_real_dic.put(count_frame, alarm_reals);
        }
        result.setTemp_real_dic(temp_real_dic);
        result.setTemp_test_dic(temp_test_dic);
        return result;
    }

    /**
     * 更新数据，包括now_real_num，now_test_num，total_real_num，total_test_num
     */
    private EventPerceiveResult getEventNum(int count_frame, EventPerceiveResult result, Alarm[] alarm_reals, Alarm[] alarm_tests) {
        List<String> match_plate = result.getMatch_plate();
        Map<String, Map<Integer, Alarm>> match_plate_dic = result.getMatch_plate_dic();
        for (Alarm alarm_real : alarm_reals) {
            result = changeNumReal(alarm_real, result);
            for (Alarm alarm_test : alarm_tests) {
                double dis_diff = calculateDistance(alarm_real, alarm_test);
                if (dis_diff <= 5) {
                    if (alarm_real.getEventType() == alarm_test.getEventType()) {
                        if (!match_plate.contains(alarm_real.getCarPlateNo()) && !match_plate.contains(alarm_test.getCarPlateNo())) {
                            alarm_real.setCountFrame(count_frame);
                            ConcurrentHashMap<Integer, Alarm> alarmMap = new ConcurrentHashMap<>();
                            alarmMap.put(0,alarm_real);
                            alarmMap.put(1,alarm_test);
                            match_plate_dic.put(alarm_real.getCarPlateNo(), alarmMap);
                            match_plate.add(alarm_real.getCarPlateNo());
                            match_plate.add(alarm_test.getCarPlateNo());

                            result = changeNumTest(alarm_test, result);


                        }
                    }
                }
            }
        }

        result.setMatch_plate_dic(match_plate_dic);
        return result;
    }

    private EventPerceiveResult changeNumTest(Alarm alarm_test, EventPerceiveResult result) {
        int[] now_test_num = result.getNow_test_num();
        int[] total_test_num = result.getTotal_test_num();

        int event_type = alarm_test.getEventType();
        if (event_type == 1) {
            now_test_num[parking_index] += 1;
            total_test_num[parking_index] += now_test_num[parking_index];
        }
        if (event_type == 6) {
            now_test_num[lane_error_index] += 1;
            total_test_num[lane_error_index] += now_test_num[lane_error_index];
        }
        if (event_type == 2 || event_type == 3) {
            now_test_num[speed_error_index] += 1;
            total_test_num[speed_error_index] += now_test_num[speed_error_index];
        }
        if (event_type == 11) {
            now_test_num[toss_error_index] += 1;
            total_test_num[toss_error_index] += now_test_num[toss_error_index];
        }
        if (event_type == 7) {
            now_test_num[occupy_error_index] += 1;
            total_test_num[occupy_error_index] += now_test_num[occupy_error_index];
        }
        if (event_type == 4) {
            now_test_num[retrograde_index] += 1;
            total_test_num[retrograde_index] += now_test_num[retrograde_index];
        }
        result.setNow_test_num(now_test_num);
        result.setTotal_test_num(total_test_num);
        return result;
    }


    private EventPerceiveResult changeNumReal(Alarm alarm_real, EventPerceiveResult result) {
        int[] now_real_num = result.getNow_real_num();
        int[] total_real_num = result.getTotal_real_num();


        int event_type = alarm_real.getEventType();
//        System.out.println(event_type);
        if (event_type == 1) {
            now_real_num[parking_index] += 1;
            total_real_num[parking_index] += now_real_num[parking_index];
        }
        if (event_type == 6) {
            now_real_num[lane_error_index] += 1;
            total_real_num[lane_error_index] += now_real_num[lane_error_index];
        }
        if (event_type == 2 || event_type == 3) {
            now_real_num[speed_error_index] += 1;
            total_real_num[speed_error_index] += now_real_num[speed_error_index];
        }
        if (event_type == 11) {
            now_real_num[toss_error_index] += 1;
            total_real_num[toss_error_index] += now_real_num[toss_error_index];
        }
        if (event_type == 7) {
            now_real_num[occupy_error_index] += 1;
            total_real_num[occupy_error_index] += now_real_num[occupy_error_index];
        }
        if (event_type == 4) {
            now_real_num[retrograde_index] += 1;
            total_real_num[retrograde_index] += now_real_num[retrograde_index];
        }

//        System.out.println(Arrays.toString(now_real_num));
        result.setNow_real_num(now_real_num);
        result.setTotal_real_num(total_real_num);
        return result;
    }

    /**
     * 计算两个系统的距离
     *
     * @param alarm_real
     * @param alarm_test
     * @return
     */
    private double calculateDistance(Alarm alarm_real, Alarm alarm_test) {
        double real_lng = Math.toRadians(alarm_real.getLng());
        double real_lat = Math.toRadians(alarm_real.getLat());
        double test_lng = Math.toRadians(alarm_test.getLng());
        double test_lat = Math.toRadians(alarm_test.getLat());

        double dLng = test_lng - real_lng;
        double dLat = test_lat - real_lat;

        double a = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(test_lat) * Math.cos(real_lat) * Math.pow(Math.sin(dLng / 2), 2);
        return  2 * Math.asin(Math.sqrt(a)) * 6371.393 * 1000;

    }

    /**
     * 判断真值系统和测试系统当前帧是否满足设定的阈值
     *
     * @param alarm_reals
     * @param alarm_tests
     * @param match_time
     * @return
     */
    private int getTimeMatchFlag(Alarm[] alarm_reals, Alarm[] alarm_tests, int match_time) {
        int match_time_flag = 0;
        for (Alarm alarm_real : alarm_reals) {
            for (Alarm alarm_test : alarm_tests) {
                long createtime_real = alarm_real.getCreateTime();
                long createtime_test = alarm_test.getCreateTime();
                long time_diff = Math.abs(createtime_real - createtime_test) / 1000;
                if (time_diff < match_time) {
                    match_time_flag = 1;
                    break;
                }
            }
        }

        return match_time_flag;
    }
}
